package org.linlinjava.litemall.db.handler;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.ibatis.type.*;
import org.linlinjava.litemall.db.dto.AdminShopSpecialDateDTO;
import java.sql.*;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@MappedTypes(List.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class AdminShopSpecialDateListHandler implements TypeHandler<List<AdminShopSpecialDateDTO>> {

    private static final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void setParameter(PreparedStatement ps, int i, List<AdminShopSpecialDateDTO> parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, toJson(parameter));
    }

    @Override
    public List<AdminShopSpecialDateDTO> getResult(ResultSet rs, String columnName) throws SQLException {
        return parseJson(rs.getString(columnName));
    }

    @Override
    public List<AdminShopSpecialDateDTO> getResult(ResultSet rs, int columnIndex) throws SQLException {
        return parseJson(rs.getString(columnIndex));
    }

    @Override
    public List<AdminShopSpecialDateDTO> getResult(CallableStatement cs, int columnIndex) throws SQLException {
        return parseJson(cs.getString(columnIndex));
    }

    private List<AdminShopSpecialDateDTO> parseJson(String json) {
        if (json == null || json.trim().isEmpty()) return Collections.emptyList();
        try {
            JsonNode arrayNode = objectMapper.readTree(json);
            List<AdminShopSpecialDateDTO> result = new ArrayList<>();
            for (JsonNode node : arrayNode) {
                long dateMillis = node.get("specialDate").asLong();
                LocalDate date = Instant.ofEpochMilli(dateMillis).atZone(ZoneId.systemDefault()).toLocalDate();

                JsonNode timeArray = node.get("specialTime");
                LocalTime[] times = new LocalTime[timeArray.size()];
                for (int i = 0; i < timeArray.size(); i++) {
                    times[i] = Instant.ofEpochMilli(timeArray.get(i).asLong())
                            .atZone(ZoneId.systemDefault()).toLocalTime();
                }
                result.add(new AdminShopSpecialDateDTO(date, times));
            }
            return result;
        } catch (Exception e) {
            throw new RuntimeException("Failed to parse JSON for AdminShopSpecialDateDTO", e);
        }
    }

    private String toJson(List<AdminShopSpecialDateDTO> list) {
        try {
            ArrayNode arrayNode = objectMapper.createArrayNode();
            for (AdminShopSpecialDateDTO dto : list) {
                ObjectNode node = objectMapper.createObjectNode();
                node.put("specialDate", dto.getSpecialDate().atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli());

                ArrayNode timeArray = objectMapper.createArrayNode();
                for (LocalTime time : dto.getSpecialTime()) {
                    long millis = time.atDate(LocalDate.ofEpochDay(0))
                            .atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
                    timeArray.add(millis);
                }
                node.set("specialTime", timeArray);
                arrayNode.add(node);
            }
            return objectMapper.writeValueAsString(arrayNode);
        } catch (Exception e) {
            throw new RuntimeException("Failed to convert AdminShopSpecialDateDTO to JSON", e);
        }
    }
}
